﻿#include "scaleslider.h"

#include <QPainter>
#include <QMouseEvent>
#include <QDebug>

ScaleSlider::ScaleSlider(QWidget *parent) : QWidget(parent)
{
    m_grooveGradientColor.first = QColor(234,235,239);
    m_grooveGradientColor.second = QColor(234,235,239);

    m_addPageGradientColor.first = QColor(27,90,238);
    m_addPageGradientColor.second = QColor(55,219,224);

    m_sliderGradientColor.first = QColor(255,255,255);
    m_sliderGradientColor.second = QColor(255,255,255);
    qDebug()<<"测试代码";
}

void ScaleSlider::initialize()
{
    is_class_initialized = true;

    //沟槽
    m_dGrooveWidth = m_dGrooveWidthScaleFactor
                        * this->width() / 100;
    m_dGrooveHeight = m_dGrooveHeightScaleFactor
                        * this->height() / 100;
    m_dXRadius = m_dGrooveWidth
                    * m_dXRadiusScaleFactor / 100;
    m_dYRadius = m_dGrooveHeight
                    * m_dYRadiusScaleFactor / 100;
    m_grooveGradient = QLinearGradient(0, 0,m_dGrooveWidth,
                                        m_dGrooveHeight);
    m_grooveGradient.setColorAt(0, m_grooveGradientColor.first);
    m_grooveGradient.setColorAt(1, m_grooveGradientColor.second);

    //刻度
    m_iSegments = m_iLargeScaleSegments * m_iSmallScaleSegments;
    m_dLargeScaleLineWidth = m_dLargeScaleLineWidthScaleFactor
                            * m_dGrooveWidth/m_iSegments / 100;
    m_dLargeScaleLineLength = m_dLargeScaleLineLengthScaleFactor
                            * m_dGrooveHeight / 100;
    m_dSmallScaleLineWidth = m_dSmallScaleLineWidthScaleFactor
                            * m_dGrooveWidth/m_iSegments / 100;
    m_dSmallScaleLineLength = m_dSmallScaleLineLengthScaleFactor
                            * m_dGrooveHeight / 100;
    m_scaleStartingPoints = QPoint(0,(m_dGrooveHeight
                                      - m_dLargeScaleLineLength)/3);

    //添加页
    m_dAddPageWidth = m_dAddPageWidthScaleFactor * this->width() / 100;
    m_dAddPageCurWidth = 0 + m_dAddPageWidth * m_dCurValue
                        /(m_dMaximum - m_dMinimum) / 100;
    m_dAddPageHeight = m_dAddPageHeightScaleFactor
                        * m_dGrooveHeight / 100;
    m_addPageGradient = QLinearGradient(0, 0,m_dAddPageWidth,
                                        m_dAddPageHeight);
    m_addPageGradient.setColorAt(0, m_addPageGradientColor.first);
    m_addPageGradient.setColorAt(1, m_addPageGradientColor.second);

    //滑块
    m_sliderGradient = QLinearGradient(0, 0,m_dSliderWidth,
                                        m_dSliderHeight);
    m_sliderGradient.setColorAt(0, m_grooveGradientColor.first);
    m_sliderGradient.setColorAt(1, m_grooveGradientColor.second);

    update();
}

void ScaleSlider::setRadius(double xRadiusScaleFactor, double yRadiusScaleFactor)
{
    if(xRadiusScaleFactor < 0)
    {
        xRadiusScaleFactor = 0;
    }

    if(xRadiusScaleFactor > 100)
    {
        xRadiusScaleFactor = 100;
    }

    if(yRadiusScaleFactor < 0)
    {
        yRadiusScaleFactor = 0;
    }

    if(yRadiusScaleFactor > 100)
    {
        yRadiusScaleFactor = 100;
    }

    m_dXRadiusScaleFactor = xRadiusScaleFactor;
    m_dYRadiusScaleFactor = yRadiusScaleFactor;
    update();
}

void ScaleSlider::setGrooveVisible(bool state)
{
    m_bGrooveVisible = state;
    update();
}

void ScaleSlider::setGrooveScaleFactor(double widthScaleFactor, double heightScaleFactor)
{
    if(widthScaleFactor < 0)
    {
        widthScaleFactor = 0;
    }

    if(widthScaleFactor > 100)
    {
        widthScaleFactor = 100;
    }

    if(heightScaleFactor < 0)
    {
        heightScaleFactor = 0;
    }

    if(heightScaleFactor > 100)
    {
        heightScaleFactor = 100;
    }

    m_dGrooveWidthScaleFactor = widthScaleFactor;
    m_dGrooveHeightScaleFactor = heightScaleFactor;
    update();
}

void ScaleSlider::setGrooveGradientColor(QPair<QColor, QColor> gradientColor)
{
    m_grooveGradientColor = gradientColor;
    m_grooveGradient = QLinearGradient(0, 0,m_dGrooveWidth,
                                        m_dGrooveHeight);
    m_grooveGradient.setColorAt(0, m_grooveGradientColor.first);
    m_grooveGradient.setColorAt(1, m_grooveGradientColor.second);
    update();
}

double ScaleSlider::maximum() const
{
    return m_dMaximum;
}

double ScaleSlider::minimum() const
{
    return m_dMinimum;
}

void ScaleSlider::setRange(double min, double max)
{
    if(min >= max)
    {
        qWarning()<<"The maximum value cannot be less than "
                    "the minimum value";
        return;
    }

    if(m_dCurValue > max)
    {
        m_dCurValue = max;
        emit sigValueChanged(m_dCurValue);
    }

    if(m_dCurValue < min)
    {
        m_dCurValue = min;
        emit sigValueChanged(m_dCurValue);
    }

    m_dMinimum = min;
    m_dMaximum = max;
    update();
}

void ScaleSlider::setScaleVisible(bool state)
{
    m_bLargeScaleVisible = state;
    m_bSmallScaleVisible = state;
    m_bScaleValueVisible = state;
    update();
}

void ScaleSlider::setScaleLineColor(QColor color)
{
    m_largeScaleLineColor = color;
    m_smallScaleLineColor = color;
    update();
}

void ScaleSlider::setScaleValueColor(QColor color)
{
    m_scaleValueColor = color;
    update();
}

void ScaleSlider::setLargeLineScaleFactor(double widthScaleFactor, double heightScaleFactor)
{
    if(widthScaleFactor < 0)
    {
        widthScaleFactor = 0;
    }

    if(widthScaleFactor > 100)
    {
        widthScaleFactor = 100;
    }

    if(heightScaleFactor < 0)
    {
        heightScaleFactor = 0;
    }

    if(heightScaleFactor > 100)
    {
        heightScaleFactor = 100;
    }

    m_dLargeScaleLineWidthScaleFactor = widthScaleFactor;
    m_dLargeScaleLineLengthScaleFactor = heightScaleFactor;
    update();
}

void ScaleSlider::setSmallLineScaleFactor(double widthScaleFactor, double heightScaleFactor)
{
    if(widthScaleFactor < 0)
    {
        widthScaleFactor = 0;
    }

    if(widthScaleFactor > 100)
    {
        widthScaleFactor = 100;
    }

    if(heightScaleFactor < 0)
    {
        heightScaleFactor = 0;
    }

    if(heightScaleFactor > 100)
    {
        heightScaleFactor = 100;
    }

    m_dSmallScaleLineWidthScaleFactor = widthScaleFactor;
    m_dSmallScaleLineLengthScaleFactor = heightScaleFactor;
    update();
}

void ScaleSlider::setLargeScaleSegments(int segments)
{
    m_iLargeScaleSegments = segments;
    m_iSegments = m_iLargeScaleSegments * m_iSmallScaleSegments;
    update();
}

void ScaleSlider::setSmallScaleSegments(int segments)
{
    m_iSmallScaleSegments = segments;
    m_iSegments = m_iLargeScaleSegments * m_iSmallScaleSegments;
    update();
}

void ScaleSlider::setScaleValueFont(QFont font)
{
    m_scaleValueFont = font;
    update();
}

void ScaleSlider::setSliderVisible(bool state)
{
    m_bSliderVisible = state;
    update();
}

void ScaleSlider::setSliderScaleFactor(double widthScaleFactor, double heightScaleFactor)
{
    if(widthScaleFactor < 0)
    {
        widthScaleFactor = 0;
    }

    if(widthScaleFactor > 100)
    {
        widthScaleFactor = 100;
    }

    if(heightScaleFactor < 0)
    {
        heightScaleFactor = 0;
    }

    if(heightScaleFactor > 100)
    {
        heightScaleFactor = 100;
    }

    m_dSliderWidthScaleFactor = widthScaleFactor;
    m_dSliderHeightScaleFactor = heightScaleFactor;
    update();
}

void ScaleSlider::setSliderColor(QColor color)
{
    m_sliderColor = color;
    update();
}

void ScaleSlider::setSliderType(ScaleSlider::SliderType type)
{
    m_sliderType = type;
    update();
}

void ScaleSlider::setSliderGradientColor(QPair<QColor, QColor> gradientColor)
{
    m_sliderGradientColor = gradientColor;
    m_sliderGradient = QLinearGradient(0, 0,m_dSliderWidth,
                                        m_dSliderHeight);
    m_sliderGradient.setColorAt(0, m_grooveGradientColor.first);
    m_sliderGradient.setColorAt(1, m_grooveGradientColor.second);
    update();
}

void ScaleSlider::setAddPageVisible(bool state)
{
    m_bAddPageVisible = state;
    update();
}

void ScaleSlider::setAddPageScaleFactor(double widthScaleFactor, double heightScaleFactor)
{
    if(widthScaleFactor < 0)
    {
        widthScaleFactor = 0;
    }

    if(widthScaleFactor > 100)
    {
        widthScaleFactor = 100;
    }

    if(heightScaleFactor < 0)
    {
        heightScaleFactor = 0;
    }

    if(heightScaleFactor > 100)
    {
        heightScaleFactor = 100;
    }

    m_dAddPageWidthScaleFactor = widthScaleFactor;
    m_dAddPageHeightScaleFactor = heightScaleFactor;
    update();
}

void ScaleSlider::setAddPageColor(QColor color)
{
    m_addPageColor = color;
    update();
}

void ScaleSlider::setAddPageGradientColor(QPair<QColor, QColor> gradientColor)
{
    m_addPageGradientColor = gradientColor;
    m_addPageGradient = QLinearGradient(0, 0,m_dAddPageWidth,
                                        m_dAddPageHeight);
    m_addPageGradient.setColorAt(0, m_addPageGradientColor.first);
    m_addPageGradient.setColorAt(1, m_addPageGradientColor.second);
    update();
}

double ScaleSlider::value() const
{
    return m_dCurValue;
}

void ScaleSlider::setValueFont(QFont font)
{
    m_curValueFont = font;
    update();
}

void ScaleSlider::setValueVisible(bool state)
{
    m_bCurValueVisible = state;
    update();
}

void ScaleSlider::setValueDisplayMode(ScaleSlider::CurValueDisplayMode mode)
{
    m_curValueDisplayMode = mode;
    update();
}

void ScaleSlider::setValueSlidable(bool state)
{
    m_bIsSlidable = state;
}

void ScaleSlider::setValue(double value)
{
    if(value > m_dMaximum)
    {
        value = m_dMaximum;
    }

    if(value < m_dMinimum)
    {
        value = m_dMinimum;
    }

    m_dCurValue = value;
    update();
    emit sigValueChanged(m_dCurValue);
}

void ScaleSlider::setFont(QFont font)
{
    m_curValueFont = font;
    update();
}

void ScaleSlider::setValueDecimal(int decimal)
{
    m_iCurValueDecimal = decimal;
    update();
}

void ScaleSlider::setValueColor(QColor color)
{
    m_curValueColor = color;
    update();
}

void ScaleSlider::setValueUnit(QString unit)
{
    m_szCurValueUnit = unit;
    update();
}

void ScaleSlider::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    m_dAddPageCurWidth = 0 + m_dAddPageWidth * m_dCurValue
                        /(m_dMaximum - m_dMinimum);

    drawGroove(&painter);
    drawAddPage(&painter);
    drawCurValue(&painter);
    drawSlider(&painter);
}

void ScaleSlider::mousePressEvent(QMouseEvent *event)
{
    if(!m_bIsSlidable)
    {
        return;
    }

    if(event->pos().x() < 0 || event->pos().x() > this->width())
    {
        if(event->pos().x() < 0)
        {
            m_dCurValue = m_dMinimum;
        }

        if(event->pos().x() > this->width())
        {
            m_dCurValue = m_dMaximum;
        }
    }
    else
    {
        m_dCurValue = m_dMaximum * double(event->pos().x()) / m_dAddPageWidth;
    }

    update();
    emit sigValueChanged(m_dCurValue);
}

void ScaleSlider::mouseMoveEvent(QMouseEvent *event)
{
    if(!m_bIsSlidable)
    {
        return;
    }

    if(event->pos().x() < 0 || event->pos().x() > this->width())
    {
        if(event->pos().x() < 0)
        {
            m_dCurValue = m_dMinimum;
        }

        if(event->pos().x() > this->width())
        {
            m_dCurValue = m_dMaximum;
        }
    }
    else
    {
        m_dCurValue = m_dMaximum * double(event->pos().x()) / m_dAddPageWidth;
    }

    update();
    emit sigValueChanged(m_dCurValue);
}

void ScaleSlider::mouseReleaseEvent(QMouseEvent *event)
{
    if(!m_bIsSlidable)
    {
        return;
    }

    if(event->pos().x() < 0 || event->pos().x() > this->width())
    {
        if(event->pos().x() < 0)
        {
            m_dCurValue = m_dMinimum;
        }

        if(event->pos().x() > this->width())
        {
            m_dCurValue = m_dMaximum;
        }
    }
    else
    {
        m_dCurValue = m_dMaximum * double(event->pos().x()) / m_dAddPageWidth;
    }

    update();
    emit sigValueChanged(m_dCurValue);
}

void ScaleSlider::resizeEvent(QResizeEvent *event)
{
    if(is_class_initialized)
    {
        calcParameters();
    }
    else
    {
        initialize();
    }
}

void ScaleSlider::calcParameters()
{
    //沟槽
    m_dGrooveWidth = m_dGrooveWidthScaleFactor
                        * this->width() / 100;
    m_dGrooveHeight = m_dGrooveHeightScaleFactor
                        * this->height() / 100;
    m_dXRadius = m_dGrooveWidth
                    * m_dXRadiusScaleFactor / 100;
    m_dYRadius = m_dGrooveHeight
                    * m_dYRadiusScaleFactor / 100;
    m_grooveGradient = QLinearGradient(0, 0,m_dGrooveWidth,
                                        m_dGrooveHeight);
    m_grooveGradient.setColorAt(0, m_grooveGradientColor.first);
    m_grooveGradient.setColorAt(1, m_grooveGradientColor.second);

    //刻度
    m_scaleStartingPoints = QPoint(0,m_dGrooveHeight/3);
    m_dLargeScaleLineWidth = m_dLargeScaleLineWidthScaleFactor
                            * m_dGrooveWidth/m_iSegments / 100;
    m_dLargeScaleLineLength = m_dLargeScaleLineLengthScaleFactor
                            * m_dGrooveHeight / 100;
    m_dSmallScaleLineWidth = m_dSmallScaleLineWidthScaleFactor
                            * m_dGrooveWidth/m_iSegments / 100;
    m_dSmallScaleLineLength = m_dSmallScaleLineLengthScaleFactor
                            * m_dGrooveHeight / 100;
    m_scaleStartingPoints = QPoint(0,(m_dGrooveHeight
                                      - m_dLargeScaleLineLength)/3);

    //添加页
    m_dAddPageHeight = m_dAddPageHeightScaleFactor
                        * m_dGrooveHeight / 100;
    m_dAddPageWidth = m_dAddPageWidthScaleFactor * this->width() / 100;
    m_addPageGradient = QLinearGradient(0, 0,m_dAddPageWidth,
                                        m_dAddPageHeight);
    m_addPageGradient.setColorAt(0, m_addPageGradientColor.first);
    m_addPageGradient.setColorAt(1, m_addPageGradientColor.second);

    //滑块
    m_sliderGradient = QLinearGradient(0, 0,m_dSliderWidth,
                                        m_dSliderHeight);
    m_sliderGradient.setColorAt(0, m_grooveGradientColor.first);
    m_sliderGradient.setColorAt(1, m_grooveGradientColor.second);
    update();
}

void ScaleSlider::drawGroove(QPainter *painter)
{
    if(!m_bGrooveVisible)
    {
        return;
    }

    painter->save();

    QPen pen;
    pen.setColor(m_grooveColor);
    pen.setCapStyle(Qt::RoundCap);
    pen.setWidthF(0.1);
    painter->setPen(pen);

    //方法1:将沟槽分为两步绘制 ①圆弧 ②直线
    //优点:圆弧部分较为顺滑,效果较好
    //缺点:填充色与自适应代码量多
//    QLineF upGrooveLine(this->width()/5, 1.5, this->width() * (4/5), 1.5);
//    QLineF downGrooveLine(this->width() * (-2/5), -this->height()/2 + 2, this->width() * (2/5), -this->height()/2 + 2);
//    painter->drawLine(upGrooveLine);
//    painter->drawLine(downGrooveLine);
//    QRectF rectangle(0, 0, this->width()/5, this->height()/5);
//    int startAngle = - 90 * 16;
//    int spanAngle = - 180 * 16;
//    painter->drawArc(rectangle, startAngle, spanAngle);


    //方法2:用圆角矩形绘制沟槽
    //优点:Qt库，稳定且代码量少
    //缺点:当边线画笔较粗时，圆弧部分锯齿较多
    painter->translate(this->width() / 2,this->height() / 2);
    painter->setBrush(m_grooveGradient);
    QRectF rectangle(-m_dGrooveWidth/2, -m_dGrooveHeight/2,
                     m_dGrooveWidth, m_dGrooveHeight);
    painter->drawRoundedRect(rectangle, m_dXRadius, m_dYRadius);

    painter->restore();

    drawScale(painter);
}

void ScaleSlider::drawScale(QPainter *painter)
{
    painter->save();

    QPen pen;
    pen.setColor(m_largeScaleLineColor);
    pen.setCapStyle(Qt::RoundCap);

    double dScaleValue = 0;

    for(int iCurSegment = 0; iCurSegment < m_iSegments; ++iCurSegment)
    {
        m_scaleStartingPoints.setX(m_dGrooveWidth
                                * double(iCurSegment)
                                / double(m_iSegments));
        if(iCurSegment % m_iSmallScaleSegments == 0)
        {
            if(!m_bScaleValueVisible)
            {
                return;
            }

            pen.setColor(m_largeScaleLineColor);
            pen.setWidthF(m_dLargeScaleLineWidth);
            painter->setPen(pen);
            painter->drawLine(m_scaleStartingPoints.x(),
                              m_scaleStartingPoints.y(),
                              m_scaleStartingPoints.x(),
                              m_scaleStartingPoints.y()
                              + m_dLargeScaleLineLength);

            if(!m_bScaleValueVisible)
            {
                return;
            }

            painter->save();
            painter->setPen(m_scaleValueColor);
            painter->setFont(m_scaleValueFont);
            dScaleValue = m_dMinimum + (m_dMaximum - m_dMinimum)
                            * iCurSegment/m_iSegments;
            painter->drawText(m_scaleStartingPoints.x() - 6,
                              m_scaleStartingPoints.y() + 32,
                              QString("%1").arg(dScaleValue));
            painter->restore();
        }
        else
        {
            if(!m_bSmallScaleVisible)
            {
                return;
            }

            pen.setColor(m_smallScaleLineColor);
            pen.setWidthF(m_dSmallScaleLineWidth);
            painter->setPen(pen);
            painter->drawLine(m_scaleStartingPoints.x(),
                              m_scaleStartingPoints.y(),
                              m_scaleStartingPoints.x(),
                              m_scaleStartingPoints.y()
                              + m_dSmallScaleLineLength);
        }
    }

    painter->restore();
}

void ScaleSlider::drawAddPage(QPainter *painter)
{
    if(!m_bAddPageVisible)
    {
        return;
    }

    painter->save();

    QPen pen;
    pen.setColor(m_addPageColor);
    pen.setCapStyle(Qt::RoundCap);
    pen.setWidthF(0.1);
    painter->setPen(pen);

    //方法1:将添加页分为两步绘制 ①圆弧 ②直线
    //优点:圆弧部分较为顺滑,效果较好
    //缺点:填充色与自适应代码量多
//    QLineF upGrooveLine(this->width()/5, 1.5, this->width() * (4/5), 1.5);
//    QLineF downGrooveLine(this->width() * (-2/5), -this->height()/2 + 2, this->width() * (2/5), -this->height()/2 + 2);
//    painter->drawLine(upGrooveLine);
//    painter->drawLine(downGrooveLine);
//    QRectF rectangle(0, 0, this->width()/5, this->height()/5);
//    int startAngle = - 90 * 16;
//    int spanAngle = - 180 * 16;
//    painter->drawArc(rectangle, startAngle, spanAngle);

    //方法2:用圆角矩形绘制添加页
    //优点:Qt库，稳定且代码量少
    //缺点:当边线画笔较粗时，圆弧部分锯齿较多
    painter->setBrush(m_addPageGradient);

    QRectF rectangle((this->width() - m_dGrooveWidth) / 2
                     , (this->height() - m_dGrooveHeight) / 2
                     , m_dAddPageCurWidth
                     , m_dGrooveHeight);
    painter->drawRoundedRect(rectangle, m_dXRadius, m_dYRadius);

    painter->restore();
}

void ScaleSlider::drawCurValue(QPainter *painter)
{
    if(!m_bCurValueVisible)
    {
        return;
    }

    painter->save();
    painter->setPen(m_curValueColor);
    painter->setFont(m_curValueFont);

    double dCurValueX = 0;
    double dCurValueY = 0;
    switch (m_curValueDisplayMode)
    {
        case ScaleSlider::OnAddPageMiddle:
        {
            dCurValueX = m_dAddPageCurWidth/2 - 15;
            dCurValueY = m_dAddPageHeight / 2 + 10;
            break;
        }
        default:
        {
            return;
        }
    }

    painter->drawText(dCurValueX, dCurValueY, QString("%1%2")
                      .arg(QString::number(m_dCurValue, 'f', m_iCurValueDecimal))
                      .arg(m_szCurValueUnit));

    painter->restore();
}

void ScaleSlider::drawSlider(QPainter *painter)
{

}
